Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ

Node / meshtastic / Meshtastic-Android / files / docs / en / developer / measurement.md

Displaying Rendered β€’ View raw β€’ Download

docs/en/developer/measurement.md 936be3998f0fe49f58b8a0f9ff2c01e3cbd85609 (936be399) Text, 5.47 KB

title: Measurement & Formatting
parent: Developer Guide
nav_order: 9
last_updated: 2026-05-13
aliases:
β€’ measurement
β€’ metric-formatter
β€’ number-formatter

Measurement & Formatting

How the Meshtastic Android/KMP app formats numbers, units, and locale-sensitive values.


Overview

All measurement data transmitted by Meshtastic radios uses metric units (meters, Β°C, hPa, m/s, etc.). The app converts and formats these values for display using two core utilities:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Utility β”‚ Location β”‚ Purpose β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838MetricFormatter β”‚ T383838core/common/.../util/MetricFormatter.kt β”‚ Converts and formats physical measu… β”‚
β”‚ T383838NumberFormatter β”‚ T383838core/common/.../util/NumberFormatter.kt β”‚ Low-level fixed-point number format… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Both live in T383838org.meshtastic.core.common.util and are available to all KMP targets (Android, Desktop, iOS).


MetricFormatter API

T383838MetricFormatter is a Kotlin T383838object with pure functions for each measurement type:

T282828
Tff7b72object T56d364MetricFormatter Tb4b4b4{
Tff7b72fun Td2a8fftemperatureTb4b4b4(Te6edf3celsiusTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3isFahrenheitTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffvoltageTb4b4b4(Te6edf3voltsTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff2Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffcurrentTb4b4b4(Te6edf3milliAmpsTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffpercentTb4b4b4(Te6edf3valueTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffhumidityTb4b4b4(Te6edf3valueTb4b4b4: Tffa657FloatTb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffpressureTb4b4b4(Te6edf3hPaTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffsnrTb4b4b4(Te6edf3valueTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffrssiTb4b4b4(Te6edf3valueTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffwindSpeedTb4b4b4(Te6edf3metersPerSecondTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffrainfallTb4b4b4(Te6edf3millimetersTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff1Tb4b4b4)Tb4b4b4: Tffa657String
Tb4b4b4}


Usage

T282828
T8b949e// Temperature β€” Fahrenheit conversion is handled automatically
Te6edf3MetricFormatterTb4b4b4.Te6edf3temperatureTb4b4b4(T79c0ff2T79c0ff2.5fTb4b4b4, Te6edf3isFahrenheit Tff7b72= Tff7b72trueTb4b4b4) T8b949e// "72.5Β°F"
Te6edf3MetricFormatterTb4b4b4.Te6edf3temperatureTb4b4b4(T79c0ff2T79c0ff2.5fTb4b4b4, Te6edf3isFahrenheit Tff7b72= Tff7b72falseTb4b4b4) T8b949e// "22.5Β°C"

T8b949e// Signal metrics
Te6edf3MetricFormatterTb4b4b4.Te6edf3snrTb4b4b4(Tff7b72-T79c0ff5.2fTb4b4b4) T8b949e// "-5.2 dB"
Te6edf3MetricFormatterTb4b4b4.Te6edf3rssiTb4b4b4(Tff7b72-T79c0ff9T79c0ff7Tb4b4b4) T8b949e// "-97 dBm"

T8b949e// Environment
Te6edf3MetricFormatterTb4b4b4.Te6edf3pressureTb4b4b4(T79c0ff1T79c0ff0T79c0ff1T79c0ff3.25fTb4b4b4) T8b949e// "1013.3 hPa"
Te6edf3MetricFormatterTb4b4b4.Te6edf3humidityTb4b4b4(T79c0ff6T79c0ff5.0fTb4b4b4) T8b949e// "65%"
Te6edf3MetricFormatterTb4b4b4.Te6edf3windSpeedTb4b4b4(T79c0ff3.7fTb4b4b4) T8b949e// "3.7 m/s"
Te6edf3MetricFormatterTb4b4b4.Te6edf3rainfallTb4b4b4(T79c0ff1T79c0ff2.3fTb4b4b4) T8b949e// "12.3 mm"

T8b949e// Power
Te6edf3MetricFormatterTb4b4b4.Te6edf3voltageTb4b4b4(T79c0ff3.95fTb4b4b4) T8b949e// "3.95 V"
Te6edf3MetricFormatterTb4b4b4.Te6edf3currentTb4b4b4(T79c0ff1T79c0ff2T79c0ff5.0fTb4b4b4) T8b949e// "125.0 mA"



NumberFormatter

T383838NumberFormatter provides locale-independent decimal formatting using pure arithmetic (no T383838String.format or T383838DecimalFormat):

T282828
Tff7b72object T56d364NumberFormatter Tb4b4b4{
Tff7b72fun Td2a8ffformatTb4b4b4(Te6edf3valueTb4b4b4: Tffa657DoubleTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657String
Tff7b72fun Td2a8ffformatTb4b4b4(Te6edf3valueTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657String
Tb4b4b4}


β”‚ Why locale-independent? Meshtastic is a mesh networking app where consistency matters β€” sensor
β”‚ readings shared between nodes should look the same everywhere. T383838NumberFormatter always uses T383838. as
β”‚ the decimal separator.


Temperature Conversion

Temperature is the only measurement that performs a unit conversion. The T383838isFahrenheit flag is typically sourced from the user's device locale or preferences:

T282828
Β°F = Β°C Γ— 1.8 + 32

All other measurements display in their native metric units. The user-facing T383838units-and-locale.md page explains what end users see.


Adding a New Measurement Type

To add a new measurement formatter:

1. Add a function to T383838MetricFormatter in T383838core/common/src/commonMain/kotlin/org/meshtastic/core/common/util/MetricFormatter.kt:

T282828
Tff7b72fun Td2a8ffradiationTb4b4b4(Te6edf3microSievertsTb4b4b4: Tffa657FloatTb4b4b4, Te6edf3decimalPlacesTb4b4b4: Tffa657Int Tff7b72= T79c0ff2Tb4b4b4)Tb4b4b4: Tffa657String Tff7b72=
Ta5d6ff"Tffd700${Te6edf3NumberFormatterTb4b4b4.Te6edf3formatTb4b4b4(Te6edf3microSievertsTb4b4b4, Te6edf3decimalPlacesTb4b4b4)Tffd700}Ta5d6ff ΞΌSv/hTa5d6ff"


2. Add tests in T383838core/common/src/commonTest/:

T282828
Tf0883e@Test
Tff7b72fun Td2a8ffradiationFormattingTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ff0.15 ΞΌSv/hTa5d6ff"Tb4b4b4, Te6edf3MetricFormatterTb4b4b4.Te6edf3radiationTb4b4b4(T79c0ff0.15fTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Ta5d6ff"Ta5d6ff1.23 ΞΌSv/hTa5d6ff"Tb4b4b4, Te6edf3MetricFormatterTb4b4b4.Te6edf3radiationTb4b4b4(T79c0ff1.234fTb4b4b4)Tb4b4b4)
Tb4b4b4}


3. Use in UI β€” call from any T383838commonMain composable or ViewModel:

T282828
Te6edf3TextTb4b4b4(Te6edf3text Tff7b72= Te6edf3MetricFormatterTb4b4b4.Te6edf3radiationTb4b4b4(Te6edf3nodeTb4b4b4.Te6edf3radiationLevelTb4b4b4)Tb4b4b4)


4. Run verification:
T282828
./gradlew :core:common:allTests


DateFormatter

Date and time formatting uses the T383838DateFormatter interface with platform-specific implementations:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Function β”‚ Output Example β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838formatRelativeTime() β”‚ "5 min ago" β”‚
β”‚ T383838formatDateTime() β”‚ "May 13, 2026 2:30 PM" β”‚
β”‚ T383838formatShortDate() β”‚ "May 13" β”‚
β”‚ T383838formatTime() β”‚ "2:30 PM" β”‚
β”‚ T383838formatTimeWithSeconds() β”‚ "2:30:45 PM" β”‚
β”‚ T383838formatDate() β”‚ "2026-05-13" β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Unlike T383838MetricFormatter, T383838DateFormatter is an interface with platform T383838expect/T383838actual implementations because date formatting inherently depends on platform locale APIs.


Design Decisions

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Decision β”‚ Rationale β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Locale-independent decimal separator (T383838.) β”‚ Mesh data shared between nodes must be consiste… β”‚
β”‚ Pure arithmetic formatting (no T383838DecimalFormat) β”‚ Works identically on JVM, Native, and JS targets β”‚
β”‚ Temperature is the only converted unit β”‚ All other metric units are universally understo… β”‚
β”‚ T383838object singleton pattern β”‚ Stateless utility β€” no instance management need… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


Related

β€’ User-facing docs: T383838docs/user/units-and-locale.md explains what end users see
β€’ Source code: T383838core/common/src/commonMain/kotlin/org/meshtastic/core/common/util/MetricFormatter.kt
β€’ Tests: T383838core/common/src/commonTest/kotlin/org/meshtastic/core/common/util/MetricFormatterTest.kt

Served by rngit 1.5.0 - Generated in 0.07s